// 文件：CertConverter.java
package net.yyge.apksigner.signer;

import net.yyge.apksigner.signer.utils.Base64;
import net.yyge.apksigner.signer.utils.KeyStoreHelper;

import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.regex.Pattern;

/**
 * 证书与密钥格式转换工具类。
 * 支持：
 * - JKS ↔ BKS 转换
 * - JKS/BKS → PK8 + PEM 转换
 */
public class CertConverter {

    // 禁止实例化，模拟 Kotlin object 的单例行为
    private CertConverter() {
        throw new AssertionError("No instances.");
    }

    /**
     * 将 JKS 或 BKS 文件转换为另一种格式（JKS ↔ BKS）
     *
     * @param inputKeyFile  输入密钥库文件 (.jks 或 .bks)
     * @param outputKeyFile 输出密钥库文件 (反向格式)
     * @param password      密钥库密码
     * @param alias         别名
     * @param aliasPassword 别名密码（密钥密码）
     * @return 是否转换成功
     */
    public static boolean convert(File inputKeyFile, File outputKeyFile,
                                  String password, String alias, String aliasPassword) {
        try (FileInputStream inputStream = new FileInputStream(inputKeyFile)) {

            KeyStore inputKeyStore;
            boolean isJks = inputKeyFile.getName().toLowerCase().endsWith(".jks");

            if (isJks) {
                inputKeyStore = KeyStoreHelper.loadJks(inputKeyFile, password.toCharArray());
            } else {
                inputKeyStore = KeyStoreHelper.loadBks(inputKeyFile, password.toCharArray());
            }

            // 创建目标密钥库（格式相反）
            KeyStore outputKeyStore;
            if (isJks) {
                outputKeyStore = KeyStoreHelper.loadBks(null, password.toCharArray()); // 创建空 BKS
            } else {
                outputKeyStore = KeyStoreHelper.loadJks(null, password.toCharArray()); // 创建空 JKS
            }

            // 获取密钥和证书链
            Key key = inputKeyStore.getKey(alias, aliasPassword.toCharArray());
            Certificate[] chain = inputKeyStore.getCertificateChain(alias);

            if (key == null || chain == null) {
                System.err.println("Error: Key or certificate chain not found for alias: " + alias);
                return false;
            }

            // 写入新密钥库
            outputKeyStore.setKeyEntry(alias, key, password.toCharArray(), chain);

            // 写出文件
            try (FileOutputStream outputStream = new FileOutputStream(outputKeyFile)) {
                outputKeyStore.store(outputStream, password.toCharArray());
            }

            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 同上，但自动获取密钥库中的第一个别名
     */
    public static boolean convert(File inputKeyFile, File outputKeyFile,
                                  String password, String aliasPassword) {
        try (FileInputStream inputStream = new FileInputStream(inputKeyFile)) {

            KeyStore inputKeyStore;
            boolean isJks = inputKeyFile.getName().toLowerCase().endsWith(".jks");

            if (isJks) {
                inputKeyStore = KeyStoreHelper.loadJks(inputKeyFile, password.toCharArray());
            } else {
                inputKeyStore = KeyStoreHelper.loadBks(inputKeyFile, password.toCharArray());
            }

            // 自动获取第一个别名
            Enumeration<String> aliases = inputKeyStore.aliases();
            if (!aliases.hasMoreElements()) {
                System.err.println("Error: No aliases found in keystore.");
                return false;
            }
            String alias = aliases.nextElement();

            KeyStore outputKeyStore;
            if (isJks) {
                outputKeyStore = KeyStoreHelper.loadBks(null, password.toCharArray());
            } else {
                outputKeyStore = KeyStoreHelper.loadJks(null, password.toCharArray());
            }

            Key key = inputKeyStore.getKey(alias, aliasPassword.toCharArray());
            Certificate[] chain = inputKeyStore.getCertificateChain(alias);

            if (key == null || chain == null) {
                System.err.println("Error: Failed to extract key or chain for alias: " + alias);
                return false;
            }

            outputKeyStore.setKeyEntry(alias, key, password.toCharArray(), chain);

            try (FileOutputStream outputStream = new FileOutputStream(outputKeyFile)) {
                outputKeyStore.store(outputStream, password.toCharArray());
            }

            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将 JKS/BKS 密钥库中的指定别名导出为 PK8 和 PEM 文件
     *
     * @param inputKeyFile  输入密钥库文件
     * @param password      密钥库密码
     * @param alias         别名
     * @param aliasPassword 别名密码
     * @param pk8File       输出 PK8 文件（私钥）
     * @param pemFile       输出 PEM 文件（证书）
     * @return 是否导出成功
     */
    public static boolean convert(File inputKeyFile, String password, String alias,
                                  String aliasPassword, File pk8File, File pemFile) {
        try (FileInputStream jksInputStream = new FileInputStream(inputKeyFile)) {

            KeyStore keyStore = KeyStoreHelper.loadKeyStore(inputKeyFile, password.toCharArray());
            Key key = keyStore.getKey(alias, aliasPassword.toCharArray());
            Certificate publicKey = keyStore.getCertificate(alias);

            if (!(key instanceof PrivateKey)) {
                System.err.println("Error: Key is not a PrivateKey.");
                return false;
            }
            if (!(publicKey instanceof X509Certificate)) {
                System.err.println("Error: Certificate is not an X509Certificate.");
                return false;
            }

            // 写 PK8 文件（原始私钥字节）
            try (FileOutputStream pk8OutputStream = new FileOutputStream(pk8File)) {
                pk8OutputStream.write(((PrivateKey) key).getEncoded());
            }

            // 写 PEM 文件（Base64 编码的证书）
            try (FileOutputStream pemOutputStream = new FileOutputStream(pemFile)) {
                pemOutputStream.write("-----BEGIN CERTIFICATE-----\n".getBytes());
                pemOutputStream.write(formatCertificate(publicKey.getEncoded()));
                pemOutputStream.write("\n-----END CERTIFICATE-----\n".getBytes());
            }

            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 同上，但使用第一个别名
     */
    public static boolean convert(File inputKeyFile, String password, String aliasPassword,
                                  File pk8File, File pemFile) {
        try (FileInputStream jksInputStream = new FileInputStream(inputKeyFile)) {

            KeyStore keyStore = KeyStoreHelper.loadKeyStore(inputKeyFile, password.toCharArray());

            Enumeration<String> aliases = keyStore.aliases();
            if (!aliases.hasMoreElements()) {
                System.err.println("Error: No aliases found in keystore.");
                return false;
            }
            String alias = aliases.nextElement();

            Key key = keyStore.getKey(alias, aliasPassword.toCharArray());
            Certificate publicKey = keyStore.getCertificate(alias);

            if (!(key instanceof PrivateKey)) {
                System.err.println("Error: Key is not a PrivateKey.");
                return false;
            }
            if (!(publicKey instanceof X509Certificate)) {
                System.err.println("Error: Certificate is not an X509Certificate.");
                return false;
            }

            try (FileOutputStream pk8OutputStream = new FileOutputStream(pk8File)) {
                pk8OutputStream.write(((PrivateKey) key).getEncoded());
            }

            try (FileOutputStream pemOutputStream = new FileOutputStream(pemFile)) {
                pemOutputStream.write("-----BEGIN CERTIFICATE-----\n".getBytes());
                pemOutputStream.write(formatCertificate(publicKey.getEncoded()));
                pemOutputStream.write("\n-----END CERTIFICATE-----\n".getBytes());
            }

            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将证书字节数组编码为 PEM 格式（Base64 + 每 64 字符换行）
     */
    private static byte[] formatCertificate(byte[] certBytes) {
        String base64 = Base64.encode(certBytes);
        // 每 64 个字符插入一个换行符
        return base64.replaceAll("(.{64})", "$1\n").getBytes();
    }
}